package com.gitee.wsl.compose.modifier.state


import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Indication
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.focusable
import androidx.compose.foundation.hoverable
import androidx.compose.foundation.interaction.InteractionSource
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.relocation.BringIntoViewRequester
import androidx.compose.foundation.relocation.bringIntoViewRequester
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusEvent
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.gitee.wsl.compose.modifier.ModifierStateScope
import com.gitee.wsl.compose.modifier.ifTrue
import kotlinx.coroutines.launch

@Composable
fun Modifier.focusBorder(
    interactionSource: InteractionSource,
    innerColor: Color = MaterialTheme.colorScheme.inversePrimary,
    outerColor: Color = MaterialTheme.colorScheme.inverseOnSurface,
    shape: Shape = FocusBorderDefaults.Shape,
    thickness: Dp = FocusBorderDefaults.Thickness,
): Modifier = composed {
    val isFocused by interactionSource.collectIsFocusedAsState()
    then(
        Modifier
            // Outer border
            .border(
                width = thickness,
                color = if (isFocused) outerColor else Color.Transparent,
                shape = shape
            )
            .padding(all = thickness * 0.75f)
            // Inner border
            .border(
                width = thickness,
                color = if (isFocused) innerColor else Color.Transparent,
                shape = shape
            )
            .padding(all = thickness)
    )
}

internal object FocusBorderDefaults {
    val Shape = RoundedCornerShape(7.dp)
    val Thickness = 3.dp
}

@Composable
fun ModifierStateScope.focusBorder(
    interactionSource: InteractionSource,
    innerColor: Color = MaterialTheme.colorScheme.inversePrimary,
    outerColor: Color = MaterialTheme.colorScheme.inverseOnSurface,
    shape: Shape = FocusBorderDefaults.Shape,
    thickness: Dp = FocusBorderDefaults.Thickness,
){
    modifier=modifier.focusBorder(interactionSource, innerColor, outerColor, shape, thickness)
}


/**
 * This modifier acquires focus to this widget as soon as the user clicks on it.
 *
 * @param interactionSource An optional [MutableInteractionSource] that will be used to track user interactions.
 * @param indication An optional [Indication] that will be shown when the widget is clicked.
 * @return A modified [Modifier] that acquires focus when the user clicks on it.
 *
 * Usage example:
 * ```
 * Box(
 *     modifier = Modifier
 *         .size(100.dp)
 *         .acquireFocusOnInteraction()
 * ) {
 *     // content here
 * }
 * ```
 *
 * @since 1.0.0
 * @author [Your name]
 */

@Deprecated("Not good solution.", level = DeprecationLevel.HIDDEN)
fun Modifier.acquireFocusOnInteraction(
    interactionSource: MutableInteractionSource? = null,
    indication: Indication? = null
): Modifier = composed {
    val interaction = interactionSource ?: remember {
        MutableInteractionSource()
    }
    val requester = remember {
        FocusRequester()
    }
    val isFocused by interaction.collectIsFocusedAsState()
    Modifier
        .focusRequester(requester)
        .focusable(true, interactionSource = interaction)
        .clickable(
            enabled = !isFocused,
            indication = indication,
            onClick = { requester.requestFocus() },
            interactionSource = remember {
                MutableInteractionSource()
            }
        )
        .then(this)
}

/**
 * Scrolls to this widget when an element is focused (i.e. user taps the input field).
 * Use on text input fields to keep them visible while editing.
 *
 * For this to work, wrap your scrollable container in another and add the .imePadding() modifier
 */
@OptIn(ExperimentalFoundationApi::class)
@Composable
 fun Modifier.bringIntoViewOnFocus(): Modifier {
    val coroutineScope = rememberCoroutineScope()
    val requester = remember { BringIntoViewRequester() }

    return bringIntoViewRequester(requester)
        .onFocusEvent {
            if (it.isFocused) {
                coroutineScope.launch {
                    requester.bringIntoView()
                }
            }
        }
}


/**
 *  Extension function to apply changes to a [Modifier] if the [Composable] is focused.
 *
 *  @param [hoverable] whether hovering is enabled and an indicator for focus.
 *  @param [focusable] whether focusing is enabled
 *  @param [interactionSource] the used [MutableInteractionSource] to indicate if a [Composable] is focused.
 *  @param [builder] apply changes to the given [Modifier].
 *  @return the [Modifier] which contains the changes of [builder] if it is focused.
 */
@Composable
fun Modifier.isFocused(
    hoverable: Boolean = true,
    focusable: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    builder: Modifier.() -> Modifier
): Modifier {
    val isHovered by interactionSource.collectIsHoveredAsState()
    val isFocused by interactionSource.collectIsFocusedAsState()

    return this.ifTrue(isHovered || isFocused) {
        builder()
    }.hoverable(
        interactionSource = interactionSource,
        enabled = hoverable
    ).focusable(
        interactionSource = interactionSource,
        enabled = focusable
    )
}